package com.mysql.transaction.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.Collections;

/**
 * @author 小木
 * @date 2021/7/6
 */
@Component
public class RedisLocker {

    private static final Logger log = LoggerFactory.getLogger(RedisLocker.class);

    private static final Long RELEASE_SUCCESS = 1L;
    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";

    private static final String MEMBER_LOCK_PREFIX = "LOYALTY:LOCK:";

    @Autowired
    private JedisCluster jedisCluster;

    /**
     * 尝试获取分布式锁
     * 注意: 底层[自动 release]资源, 所以不需要手动[finally]释放, 而且因为[JedisCluster]是单例的, 所以一旦 close(), 那么后续操作就会报错!
     *
     * @param lockKey    锁
     * @param requestId  请求标识
     * @param expireTime 超期时间 -> 毫秒
     * @return 是否获取成功
     */
    public boolean lock(String lockKey, String requestId, int expireTime) {

        try {
            String result = jedisCluster.set(MEMBER_LOCK_PREFIX + lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
            return LOCK_SUCCESS.equals(result);

        } catch (Exception e) {
            log.error(String.format("Redis lock error!: %s", e));
        }
        return false;

    }


    /**
     * 释放分布式锁
     *
     * @param lockKey   锁
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public boolean unlock(String lockKey, String requestId) {
        try {

            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            Object result = jedisCluster.eval(script, Collections.singletonList(MEMBER_LOCK_PREFIX + lockKey), Collections.singletonList(requestId));

            return RELEASE_SUCCESS.equals(result);
        } catch (Exception e) {
            log.error(String.format("Redis unlock error!: %s", e));
        }
        return false;

    }
}
